import { Button, Cascader, DatePicker, Input, Select, Space } from 'antd'
import { isEqual } from 'lodash-es'
import React, { useEffect, useState } from 'react'

import { getAppState, getBasicFn } from '@/utils/dvaUtil/index'

import AekCascader from '../AekCascader'
import AekSelect from '../AekSelect'
import AekTreeSelect from '../AekTreeSelect'

import styles from './index.module.less'

/**
 * @typedef {'Input' | 'Select' | 'DatePicker' | 'RangePicker'| 'AekSelect' | 'AekTreeSelect' | 'AekCascader'} ComponentNameProps
 */

/**
 * @typedef {Omit<import('rc-picker/lib/PickerPanel').PickerPanelProps<DateType>, ''>} DatePickerProps
 */

/**
 * @typedef { import("react").CSSProperties &
 * import("antd/es/input").InputProps &
 * import("antd/es/input-number").InputNumberProps &
 * import("antd/es/select").SelectProps &
 * import("antd/es/cascader").CascaderProps &
 * import("antd/es/date-picker").DatePickerProps &
 * import("antd/es/tree-select").TreeSelectProps &
 * import("../AekSelect").AekSelectProps &
 * import("../AekTreeSelect").AekTreeSelectProps &
 * import("../AekCascader").AekCascaderProps &
 * {}
 * } ComponentPropsProps
 */

/**
 * @typedef {Object} ComponentProps
 * @property {ComponentNameProps} [name] 组件名或者组件
 * @property {ComponentPropsProps} [props] 组件属性
 */

/**
 * @typedef {Object} FormDataProps
 * @property {boolean} [exclude] 是否排除
 * @property {string} [label] 描述
 * @property {string} [field] 字段名
 * @property {ComponentProps} [component] 组件
 */

/**
 * @typedef {Object} SearchFormProps
 * @property {object} [searchParams] 搜索参数
 * @property {FormDataProps[]} [formData] 第一行搜索表单配置
 * @property {function({})} [onSearch] 搜索回调函数
 */

const { toAction } = getBasicFn({ namespace: 'app' })

/**
 * @param {SearchFormProps} props
 * @returns
 */
const SearchForm = props => {
  const { searchParams, formData, onSearch, className } = props

  const [defaultSearchParams, setDefaultSearchParams] = useState({})
  const [valueObj, setValueObj] = useState({})

  const initSearchParams = () => {
    const app = getAppState()
    const pageKey = window.location.hash.split('?')[0].split('/').slice(-1)
    const { searchParamsCache } = app
    if (searchParamsCache) {
      if (searchParamsCache[pageKey]) {
        setDefaultSearchParams(searchParamsCache[pageKey])
        return
      }
      toAction({ searchParamsCache: { ...searchParamsCache, [pageKey]: searchParams } })
    } else {
      toAction({ searchParamsCache: { [pageKey]: searchParams } })
    }
    setDefaultSearchParams(searchParams)
  }

  useEffect(() => {
    initSearchParams()
  }, [])

  useEffect(() => {
    if (isEqual(valueObj, searchParams)) return
    setValueObj(searchParams)
  }, [JSON.stringify(searchParams)])

  /**
   *
   * @param {{}} obj
   * @param {boolean} search 是否搜索，默认是
   */
  const setValue = (obj, search = true) => {
    const newValue = { ...valueObj, ...obj }
    const finalObj = {}
    for (let key of Object.keys(newValue)) {
      let value = newValue[key]
      if (Object.prototype.toString.call(value) === '[object Object]') {
        if (Object.values(value).some(item => item !== undefined && item !== null && item !== '')) {
          finalObj[key] = value
        }
      } else if (value !== undefined && value !== null && value !== '') {
        finalObj[key] = value
      }
    }
    setValueObj(finalObj)
    if (search && onSearch) {
      onSearch(finalObj)
    }
  }

  /** 搜索 */
  const searchHandler = () => {
    if (onSearch) {
      onSearch(valueObj)
    }
  }

  /** 重置搜索 */
  const reset = () => {
    setValueObj(defaultSearchParams)
    if (onSearch) {
      onSearch(defaultSearchParams)
    }
  }

  /** 输入组件 */
  const createInput = ({ component, label, field }) => {
    const { props = {} } = component
    const { placeholder, ...otherProps } = props
    return (
      <Input
        {...otherProps}
        style={{ width: 140 }}
        placeholder={placeholder || `请输入${label}`}
        value={valueObj[field]}
        allowClear
        onChange={e => {
          const { value } = e.target
          setValue({ [field]: value }, value === '')
        }}
        onPressEnter={searchHandler}
      />
    )
  }

  /** 选择组件 */
  const createSelect = ({ component, label, field }) => {
    const { props = {} } = component
    const { placeholder, mode, ...otherProps } = props
    return (
      <div className={mode === 'multiple' ? 'multipleSelect' : ''}>
        <Select
          {...otherProps}
          mode={mode}
          style={{ width: 140 }}
          placeholder={placeholder || `请选择${label}`}
          value={valueObj[field]}
          allowClear
          onChange={value => {
            setValue({ [field]: value })
          }}
        />
      </div>
    )
  }

  /** 多级选择组件 */
  const createCascader = ({ component, label, field }) => {
    const { props } = component
    const { placeholder, ...otherProps } = props
    return (
      <Cascader
        {...otherProps}
        style={{ width: 140 }}
        placeholder={placeholder || `请选择${label}`}
        value={valueObj[field]}
        onChange={value => {
          setValue({ [field]: value })
        }}
      />
    )
  }

  /** 多级选择组件 */
  const createAekCascader = ({ component, label, field }) => {
    const { props } = component
    const { placeholder, ...otherProps } = props
    return (
      <AekCascader
        {...otherProps}
        style={{ width: 140 }}
        placeholder={placeholder || `请选择${label}`}
        value={valueObj[field]}
        onChange={value => {
          setValue({ [field]: value })
        }}
      />
    )
  }

  /** 选择组件 */
  const createAekSelect = ({ component, label, field }) => {
    const { props = {} } = component
    const { placeholder, mode, ...otherProps } = props
    return (
      <div className={mode === 'multiple' ? 'multipleSelect' : ''}>
        <AekSelect
          style={{ width: 140 }}
          {...otherProps}
          mode={mode}
          placeholder={placeholder || `请选择${label}`}
          value={valueObj[field]}
          onChange={value => {
            setValue({ [field]: value })
          }}
        />
      </div>
    )
  }

  /** 选择组件 */
  const createAekTreeSelect = ({ component, label, field }) => {
    const { props = {} } = component
    const { placeholder, multiple, ...otherProps } = props
    return (
      <div className={multiple ? 'multipleSelect' : ''}>
        <AekTreeSelect
          {...otherProps}
          multiple={multiple}
          style={{ width: 140 }}
          placeholder={placeholder || `请选择${label}`}
          value={valueObj[field]}
          onChange={value => {
            setValue({ [field]: value })
          }}
        />
      </div>
    )
  }

  /** 普通时间组件 */
  const createDatePicker = ({ field, component }) => (
    <DatePicker
      {...component?.props}
      value={valueObj[field]}
      onChange={value => {
        setValue({ [field]: value })
      }}
    />
  )

  /** 普通时间范围组件 */
  const createRangePicker = ({ component, field }) => (
    <DatePicker.RangePicker
      {...component?.props}
      value={valueObj[field]}
      onChange={value => {
        setValue({ [field]: value })
      }}
    />
  )

  /**
   * @param {FormDataProps} data
   * @param {*} index
   * @returns
   */
  const generateComponent = (data, index) => {
    const { exclude, field, label, component } = data
    if (exclude) {
      return null
    }
    let relComponent
    const { name: ComonentName } = component
    if (React.isValidElement(component)) {
      relComponent = component
    } else if (typeof component === 'number' || typeof component === 'string') {
      relComponent = <Input style={{ width: 140 }} readOnly value={component} />
    } else {
      const funMap = {
        Input: createInput,
        Select: createSelect,
        Cascader: createCascader,
        AekCascader: createAekCascader,
        AekSelect: createAekSelect,
        AekTreeSelect: createAekTreeSelect,
        DatePicker: createDatePicker,
        RangePicker: createRangePicker,
      }

      let Com = funMap[ComonentName]
      if (!Com) {
        throw new Error(`不存在该组件：${ComonentName}`)
      }
      relComponent = Com(data)
    }

    return (
      <div key={field || index} className={styles.wrapper}>
        <Space.Compact>
          {label && <Button className='min-w72px py4px px7px'>{label}</Button>}
          {relComponent}
        </Space.Compact>
      </div>
    )
  }

  return (
    <div className={`flex ${className}`}>
      <div className='flex-grow-1 flex flex-wrap'>
        {formData.map((data, index) => generateComponent(data, index))}
        <div className='mb10px order-last'>
          <Button type='primary' ghost onClick={searchHandler}>
            搜索
          </Button>
          <Button onClick={reset}>重置</Button>
        </div>
      </div>
    </div>
  )
}

export default SearchForm
